package main

import "path"

import (
	"fmt"
	"io/fs"
	"os"
	"slices"
	"strings"
)

const Sep = 5

// 判断一个full path是否是排除的
func isExclude(p string) bool {
	basePath, _ := folderPath.Get()

	for _, v := range excludePaths {
		if matched, _ := path.Match(path.Join(basePath, v), p); matched {
			return true
		}
	}
	return false
}

func sortInfos(infos []os.FileInfo) {
	slices.SortFunc(infos, func(a, b fs.FileInfo) int {
		if a.IsDir() && b.IsDir() {
			return 0
		} else if !a.IsDir() && b.IsDir() {
			return 1
		} else {
			return -1
		}
	})
}

func CreateFNode(p string) *FNode {
	return &FNode{
		Path:     p,
		Name:     path.Base(p),
		Depth:    0,
		IsLast:   false,
		IsDir:    true,
		Father:   nil,
		Children: make([]*FNode, 0),
	}
}

// FNode 文件节点， 生成树状目录的核心类
type FNode struct {
	Path     string
	Name     string
	Depth    int
	IsLast   bool // 是否是父节点的最后一个孩子
	IsDir    bool
	Father   *FNode
	Children []*FNode
}

// BuildTree 初始化整棵树
func (f *FNode) BuildTree() {

	// 如果该文件不是目录，直接return
	if !f.IsDir {
		return
	}

	entries, err := os.ReadDir(f.Path)
	if err != nil {
		fmt.Println(err.Error())
	}
	infos := make([]fs.FileInfo, 0, len(entries))
	for _, entry := range entries {
		info, err := entry.Info()
		if err != nil {
			fmt.Println(err.Error())
		}
		infos = append(infos, info)
	}

	// 有时候会对目录里的文件进行排序，暂时没加这个功能
	//sortInfos(infos)

	for index, info := range infos {
		// 如果是被排除的文件，那么忽略
		if isExclude(path.Join(f.Path, info.Name())) {
			continue
		}
		f.Children = append(f.Children, &FNode{
			Path:     path.Join(f.Path, info.Name()),
			Depth:    f.Depth + 1,
			IsLast:   index == len(infos)-1,
			IsDir:    info.IsDir(),
			Name:     info.Name(),
			Father:   f,
			Children: make([]*FNode, 0),
		})
	}

	// 对每个子文件进行建树操作
	for _, c := range f.Children {
		c.BuildTree()
	}

}

// GenerateTreeStr 深搜整棵树，返回根节点的结果字符串
func (f *FNode) GenerateTreeStr() string {
	res := ""
	res += f.formatStr() + "\n"
	for _, c := range f.Children {
		res += c.GenerateTreeStr()
	}
	return res
}

// 工具函数
func (f *FNode) repeatStr(str string, cnt int) string {
	res := ""
	for i := 0; i < cnt; i++ {
		res += str
	}
	return res
}

// 找到所有的IsLast为false的直系父节点
func (f *FNode) getNLF() []*FNode {
	if f.Father == nil {
		return []*FNode{}
	}
	if !f.Father.IsLast {
		return append(f.Father.getNLF(), f.Father)
	}
	return f.Father.getNLF()
}

// 生成一个节点在目录树中对应的那一行的字符串
func (f *FNode) formatStr() string {
	res := ""
	nlf := f.getNLF()

	res += f.repeatStr(" ", f.Depth*Sep)

	sr := strings.Split(res, "")

	for _, v := range nlf {
		if v.Depth > 0 {
			sr[v.Depth*Sep] = "│"
		}
	}

	res = strings.Join(sr, "")

	if f.IsLast {
		res += "└" + f.repeatStr("─", Sep-2) + " "
	} else {
		res += "├" + f.repeatStr("─", Sep-2) + " "
	}

	res += f.Name

	return res
}
